package top.codecrab.volatile_;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author codecrab
 * @since 2021年06月29日 11:12
 */
class User {
    private String username;
    private Integer age;
}

public class ABADemo {

    static AtomicInteger atomicInteger = new AtomicInteger(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    /**
     * t1和t2线程 演示ABA问题
     * t3和t4线程，解决ABA问题
     */
    public static void main(String[] args) {
        System.out.println("====== ABA演示 ======");
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t初始值：" + atomicInteger.get());
            atomicInteger.compareAndSet(100, 101);
            System.out.println(Thread.currentThread().getName() + "\t第一次修改：" + atomicInteger.get());
            atomicInteger.compareAndSet(101, 100);
            System.out.println(Thread.currentThread().getName() + "\t第二次修改：" + atomicInteger.get());
        }, "t1").start();

        new Thread(() -> {
            //睡一秒，等待t1线程完成两次操作
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean set = atomicInteger.compareAndSet(100, 101);
            System.out.println(Thread.currentThread().getName() + "\t尝试修改：" + set + "，当前值：" + atomicInteger.get());
        }, "t2").start();

        new Thread(() -> {
            //睡3秒，确保t4获取到最初的版本号
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("====== ABA解决 ======");
            System.out.println(Thread.currentThread().getName() + "\t初始值：" + atomicStampedReference.getReference() + "，版本：" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t第一次修改：" + atomicStampedReference.getReference() + "，版本：" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t第二次修改：" + atomicStampedReference.getReference() + "，版本：" + atomicStampedReference.getStamp());
        }, "t3").start();

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean set = atomicStampedReference.compareAndSet(100, 101, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "\t尝试修改：" + set + "，当前值：" + atomicStampedReference.getReference() + "，版本号：" + atomicStampedReference.getStamp());
        }, "t4").start();
    }
}
